#pragma once

#include <list>

#include "listeners.h"
#include "Passenger.h"
#include "FloorsContainer.h"

struct CallRequest
{
	size_t fromFloor;
	bool upDirection;
	CallRequest(size_t floorToCall, bool goingUp) : fromFloor(floorToCall), upDirection(goingUp) {};
	bool operator==(const CallRequest& r)
	{
		return (fromFloor == r.fromFloor) && (upDirection == r.upDirection);
	}
};

class CElevator : public IElevator
{
	typedef std::list<CallRequest> CallRequestRegistry;
public:
	CElevator(size_t capacity);
	~CElevator(void);

	void SetFloorsContainer(IFloorsContainer* container);
	void StartMove();

	virtual const PassengerCollection& GetLoadedPassengers() const { return m_passengers; };
	virtual size_t GetElevatorPos() const { return m_curFloor; };
	virtual bool UpDirection() const { return m_upDirection; };
	virtual size_t GetCapacity() const { return m_capacity; };
	virtual size_t GetAverageWaitTime() const { return m_avgWaitTime; };
	
	void SetUpdateListener(IUpdateListener* l);
	void SetActionListener(IElevatorActionListener* l);
	void SetTransportedListener(IPassengertransportedListener* l);
	void SetIncomingPassengersListener(ILoadPassengersListener* l);
private:
	void MoveUp();
	void MoveDown();
	void UnloadPassengers();
	void UpdateCalls();
	void FireAction();
	void PassengersLoaded();
	void RecalculateAvgWaitTime();

	IPassengertransportedListener* m_transportedListener;
	IElevatorActionListener* m_actionListener;
	IUpdateListener* m_updateListener;
	ILoadPassengersListener* m_loadPassengersListener;
	
	IFloorsContainer* m_floorsContainer;
	size_t m_curFloor;
	size_t m_capacity;
	bool m_upDirection;
	size_t m_avgWaitTime;
	std::vector<size_t> m_waitingData;

	PassengerCollection m_passengers;
	std::vector<size_t> m_passengerToExit;
	CallRequestRegistry m_currentCallRequests, m_incomingCallRequests;

	class CElevatorListener
	{
	protected:
		CElevator& m_elevator;
		CElevatorListener(CElevator& el) : m_elevator(el){}
	};

	struct CPassengerArrivedListener : public IPassengerListener, CElevatorListener
	{
		CPassengerArrivedListener(CElevator& el) : CElevatorListener(el) {};
		virtual void OnPassengerArrived(CPassenger* passenger);
	};

	struct CIncomingPassengersListener : public ILoadPassengersListener, CElevatorListener
	{
		CIncomingPassengersListener(CElevator& el) : CElevatorListener(el) {};
		virtual void LoadPassengersAtArival(PassengerCollection& incomingPassengers);
	};

	struct CallRequestlistener : public ICallRequestListener, CElevatorListener
	{
		CallRequestlistener(CElevator& el) : CElevatorListener(el) {};
		virtual void OnCallRequest(size_t from, bool upDirection);
	};
};

